//
// Created by chao.li on 2023/10/30.
//

#include "LParser.h"
using namespace l_sys;
l_express::l_express(const std::string& str)
{
    for (int i = 0; i < str.size(); ++i) {
        actList.emplace_back(str[i]);
    }
}

l_express::l_express(const l_express &e)
{
    for (int i = 0; i < e.actList.size(); ++i) {
        actList.emplace_back(e.actList[i]);
    }
}

void l_express::apply(const l_rule &rule)
{
    std::vector<l_action> res;

    for ( auto iter = actList.begin();
          iter !=  actList.end(); ++iter) {
        if(iter->ch == rule.first.ch){
            res.insert(res.end(), rule.second.begin(), rule.second.end());
        } else{
            res.push_back(*iter);
        }
    }

    actList.clear();
    actList.insert(actList.begin(), res.begin(), res.end());
}

l_express &l_express::operator=(const l_express &str)
{
    actList.clear();
    actList.insert(actList.begin(), str.actList.begin(), str.actList.end());
    return *this;
}

l_rule::l_rule(const std::string &str):
    first(str[0])
{
    // 跳过等号 =
    for (int i = 2; i <str.size(); ++i) {
        second.emplace_back(str[i]);
    }
}

void l_program::parse(const std::string &programStr)
{
    std::stringstream ss(programStr);
    std::string temp;
    get_word(ss, name);
    get_word(ss, temp);  // {
    get_word(ss, temp);  // Angle
    ss >> angle;              // 6
    get_word(ss, temp);  // Axiom
    get_word(ss, axiom);

    std::string rule;
    rules.clear();
    while(!ss.eof() && get_word(ss, rule)){
        if(rule.find('=') != std::string::npos)
            rules.push_back(rule);
    }
}

bool l_program::get_word(std::stringstream &ss, std::string &word)
{
    std::string temp;
    char line[MAX_LINE_CHAR_NUM];
    while(ss>>temp){
        if(temp.find(';') != std::string::npos){
            temp = temp.substr(0, temp.find(';'));
            ss.getline(line, MAX_LINE_CHAR_NUM, '\n');
        }
        if(!temp.empty()){
            word = temp;
            return true;
        }
    }
    return false;
}

bool l_program::is_white_space(const std::string &word)
{
    static wchar_t white[] = {
            ' ','\r', '\n', '\t',
    };
    for (auto c : word) {
        bool isWhite = false;
        for (auto f: white) {
            if(f == c){
                // white
                isWhite = true;
                break;
            }
        }
        if(!isWhite){
            return false;
        }
    }
    return true;
}
/**
已经实现：
F       从当前位置向前走一步，同时画线
G       从当前位置向前走一步，但不画线
+       从当前方向向左转一个给定的角度
-       从当前方向向右转一个给定的角度
|       原地转向 180°
[       Push,将龟图当前状态压进栈(stack)
]       Pop,将图形状态重置为栈顶的状态, 并去掉该栈中的内容

待实现：
\nn     增加角度 nn 度
/nn     减少角度 mn 度
Cnn     选择颜色 nn
<nn     在此基础上增加颜色 nn
>nn     在此基础上减少颜色 nn
!       倒转方向(控制+,-,/)
@nn     将线段长度乘以 nnn，nnn 也可以是简单函数其他

其他      也是合法的，主要用于获得复杂的解释
**/
void l_action::execute(l_mac& machine)
{
    switch (ch) {
        case 'F':
        {
            auto start = machine.cur_state.pos;
            start = vec2(round(start.x), round(start.y));
            machine.cur_state.add_step();
            auto end = machine.cur_state.pos;
            end = vec2(round(end.x), round(end.y));
            machine.draw_line(start, end, machine.cur_state.paint);
            break;
        }
        case 'G':
        {
            machine.cur_state.add_step();
            break;
        }
        case '+':
        {
            machine.cur_state.add_degree(machine.get_degree());
            break;
        }
        case '-':
        {
            machine.cur_state.add_degree(-machine.get_degree());
            break;
        }
        case '|':
        {
            machine.cur_state.add_degree(drawer_basic::PI);
            break;
        }
        case '[':
        {
            machine.push_stack();
            break;
        }
        case ']':
        {
            machine.pop_stack();
            break;
        }
        default:
        {
//            std::cout << "未实现的动作：" << ch << std::endl;
        }
    }
}
